<?php

/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace youmbe\phpword\models;

use Yii;
use common\models\contract\ContractPageTexts;
use yii\helpers\ArrayHelper;

/**
 * Html provides a set of static methods for generating commonly used HTML tags.
 *
 * Nearly all of the methods in this class allow setting additional html attributes for the html
 * tags they generate. You can specify, for example, `class`, `style` or `id` for an html element
 * using the `$options` parameter. See the documentation of the [[tag()]] method for more details.
 *
 * For more details and usage information on Html, see the [guide article on html helpers](guide:helper-html).
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class ContentModel extends \yii\base\Model {

    /**
     * @var ContractPageTexts
     */
    public $model;

    /**
     * @var string
     */
    public $content;

    /**
     * @var string
     */
    public $param;

    /**
     * @var string
     */
    public $format;

    /**
     * @var array
     */
    private $_paragraphs = [];

    /**
     * @var array
     */
    private $_params = [];

    /**
     * {@inheritdoc}
     */
    public function rules() {
        return [
            [['model', 'content'], 'required'],
            [['content', 'param', 'format'], 'string'],
            [['param'], 'validateParam'],
            [['content'], 'validateContent'],
        ];
    }

    public function validateContent($attribute) {
        if ($this->hasErrors()) {
            return;
        }
        $paragraphs = explode(PHP_EOL, $this->$attribute);
        $translateParams = $this->getTranslateParams();
        $res = [];
        $mutilLines = [];
        $mindex = 0;
        foreach ($paragraphs as $para) {
            $pattern = "/{(.*?)}/";
            $ps = [];
            $html = preg_replace_callback($pattern, function ($matches) use(&$ps) {
                $ps[] = $matches[1];
                return preg_replace('/({.*?})/', PHP_EOL, $matches[0]);
            }, $para);
            $d = explode(PHP_EOL, $html);
            $lines = [];
            foreach ($d as $k => $item) {
                if (!empty($item)) {
                    $lines[] = $item;
                }
                $paramAliasName = ArrayHelper::getValue($ps, $k);
                if (!$paramAliasName) {
                    continue;
                }
                if (isset($translateParams[$paramAliasName])) {
                    $rawData = $translateParams[$paramAliasName];
                } else {
                    $rawData = $this->translateParamToText($paramAliasName);
                }
                if (!is_array($rawData)) {
                    $lines[] = [
                        'text' => $rawData,
                        'style' => 'underline',
                    ];
                    continue;
                }
                $lines[] = '{replace.' . $mindex . '}';
                $mutilLines[$mindex] = $rawData;
                $mindex++;
            }
            $res[] = $lines;
        }
        if (!empty($mutilLines)) {
            $res = static::appendFormatLines($res, $mutilLines);
        }
        $this->_paragraphs = $res;
    }

    protected static function appendFormatLines($lines, $replace) {
        $new = [];
        foreach ($lines as $line) {
            foreach ($line as $raw) {
                if (!is_string($raw)) {
                    $new[] = $raw;
                    continue;
                }
                preg_match_all('/{replace\.(.*)}/', $raw, $match);
                if (empty($match[1])) {
                    $new[] = (array) $raw;
                    continue;
                }
                $mlines = ArrayHelper::getValue($replace, $match[1][0]);
                $new = ArrayHelper::merge($new, $mlines);
            }
        }
        return $new;
    }

    /**
     * @param array $attributes
     * @return array|null
     */
    public function paramsPreProcessor($attributes = []) {
        $params = $this->getParams();
        $args = [];
        foreach ($params as $key => $vls) {
            $options = $this->translateParamOptions;
            $attribute = null;
            $value = null;
            if (is_int($key) && is_string($vls)) {
                $attribute = $vls;
            } elseif (is_array($vls)) {
                $attribute = ArrayHelper::getValue($vls, 'attribute');
                $value = ArrayHelper::getValue($vls, 'value');
                $options = ArrayHelper::merge($options, ArrayHelper::getValue($vls, 'options', []));
            }
            if (!in_array($attribute, $attributes)) {
                continue;
            }
            if ($this instanceof ContractPage) {
                $attribute = ltrim($attribute, 'page.');
            }
            if ($value == null) {
                $value = ArrayHelper::getValue($this, $attribute);
            }
            if (!$value) {
                $value = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
                Html::addCssClass($options, 'border-color-danger');
            }
            $tag = ArrayHelper::remove($options, 'tag', 'span');
            $args[$attribute] = Html::tag($tag, $value, $options);
        }
        return $args;
    }

    /**
     * @param string $attribute
     * @return array|null
     */
    public function translateParamToText($attribute) {
        $model = $this->model;
        if ($model instanceof ContractPage) {
            $attribute = ltrim($attribute, 'page.');
        }
        try {
            if (strpos($attribute, ':') !== false || in_array($attribute, $model->globalTranslateSymbols)) {
                $value = $model->translateGlobalParams($attribute);
            } else {
                $value = ArrayHelper::getValue($model, $attribute);
            }
        } catch (UnknownPropertyException $e) {
            $value = $attribute;
        }
        if (!$value) {
            $value = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
        }
        return $value;
    }

    public function validateParam($attribute) {
        if ($this->hasErrors()) {
            return;
        }
        if (!$this->$attribute) {
            return;
        }
        $params = unserialize($this->$attribute);
        if (empty($params)) {
            return;
        }
        $this->_params = $params;
    }

    /**
     * @var array 默认参数转换配置
     */
    public $translateParamOptions = [
        'class' => 'underline',
        'tag' => 'span',
    ];

    /**
     * @var array 默认参数转换配置
     */
    public $globalTranslateSymbols = [
        'MULTILINES',
        'SPACE',
        'COPIES',
        'ATTACH',
    ];

    /**
     * @return array
     */
    public function getParams() {
        return $this->_params;
    }

    /**
     * @return array
     */
    public function getTranslateParams() {
        $params = $this->getParams();
        if (!empty($params) && is_array($params)) {
            return ArrayHelper::map($params, 'attribute', 'value');
        }
        return [];
    }

    /**
     * @return array
     */
    public function getParagraphs() {
        return $this->_paragraphs;
    }

    public function save() {
        if (!$this->validate()) {
            return;
        }
        return $this->getParagraphs();
    }

    /**
     * @param array $attributes
     * @return array|null
     */
    public function translateParams($attributes = []) {
        $params = $this->getParams();
        $args = [];
        foreach ($params as $key => $vls) {
            $options = $this->translateParamOptions;
            $attribute = null;
            $value = null;
            if (is_int($key) && is_string($vls)) {
                $attribute = $vls;
            } elseif (is_array($vls)) {
                $attribute = ArrayHelper::getValue($vls, 'attribute');
                $value = ArrayHelper::getValue($vls, 'value');
                $options = ArrayHelper::merge($options, ArrayHelper::getValue($vls, 'options', []));
            }
            if (!in_array($attribute, $attributes)) {
                continue;
            }
            if ($this instanceof ContractPage) {
                $attribute = ltrim($attribute, 'page.');
            }
            if ($value == null) {
                $value = ArrayHelper::getValue($this, $attribute);
            }
            if (!$value) {
                $value = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
                Html::addCssClass($options, 'border-color-danger');
            }
            $tag = ArrayHelper::remove($options, 'tag', 'span');
            $args[$attribute] = Html::tag($tag, $value, $options);
        }
        foreach ($attributes as $attribute) {
            if ($this instanceof ContractPage) {
                $attribute = ltrim($attribute, 'page.');
            }
            if (isset($args[$attribute])) {
                continue;
            }
            $options = $this->translateParamOptions;
            $tag = ArrayHelper::remove($options, 'tag', 'span');
            try {
                if (strpos($attribute, ':') !== false || in_array($attribute, $this->globalTranslateSymbols)) {
                    $value = $this->translateGlobalParams($attribute, $options);
                } else {
                    $value = ArrayHelper::getValue($this, $attribute);
                }
            } catch (UnknownPropertyException $e) {
                $value = $attribute;
                $tag = 's';
                Html::addCssClass($options, 'border-color-danger text-danger');
            }
            if (!$value) {
                $value = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
                Html::addCssClass($options, 'border-color-danger');
            }
            $args[$attribute] = Html::tag($tag, $value, $options);
        }
        return $args;
    }

    public function getTranslateHtml($attribute, $options = []) {
        $value = trim($this->$attribute);
        if (empty($value)) {
            return null;
        }
        $tag = ArrayHelper::remove($options, 'tag', 'p');
        $convertWarp = true;
        if ($value != strip_tags($value, '<br>')) {
            $convertWarp = false;
        }
        preg_match_all('/{(.*?)}/', $value, $match);
        $params = $this->translateParams($match[1]);
        $content = Yii::t('message', $value, $params);
        if ($convertWarp === false) {
            return Html::tag($tag, $content, $options);
        }
        return Html::convertWrap($tag, $content, $options);
    }

    /**
     * 换行转html标签
     *
     * @param $attribute
     * @return string
     * @throws UnknownPropertyException
     */
    public function translateGlobalParams($attribute, &$options = []) {
        $args = explode(':', $attribute);
        $key = ArrayHelper::getValue($args, 0);
        if (!$key) {
            throw new UnknownPropertyException('Property: "' . $attribute . '" parameter does not exist.');
        }
        if (strpos($key, 'MULTILINES') !== false) {
            $length = (int) ArrayHelper::getValue($args, 1, 7);
            return str_pad("&nbsp;", 6 * 124 * $length, "&nbsp;");
        }
        if (strpos($key, 'SPACE') !== false) {
            $length = (int) ArrayHelper::getValue($args, 1, 1);
            return str_pad("&nbsp;", 6 * 20 * $length, "&nbsp;");
        }
        if (strpos($key, 'COPIES') !== false) {
            $copies = $this->contract ? $this->contract->copies : 2;
            $party = ArrayHelper::getValue($args, 1);
            if ($party !== null) {
                return $copies / 2;
            }
            return $copies;
        }
        if (strpos($key, 'ATTACH') !== false) {
            $id = ArrayHelper::getValue($args, 1);
            $type = ArrayHelper::getValue($args, 2);
            $contract_id = $this->contract_id;
            $condition = compact('id', 'contract_id', 'type');
            if (!empty($condition)) {
                Html::removeCssClass($options, 'underline');
                $page = static::findPageByCondition($condition);
                if ($page && $page instanceof ContractPage) {
                    return $page->getAttachTitle();
                }
            }
            return '附件';
        }
        return false;
    }

}
